﻿#include "db_api_.h"

const int DB_VERSION = (SORT << 24) + (0 << 16) + (2 << 8) + (14); // 功能1.功能2.大版本.小版本（8.8.8.8）

#ifndef _WIN32
extern uint8_t sdmmc_disk_check(int);
#endif

DBCONTENT * hDB = 0;

int init_check(void);

int _db_init(db_cb cb, get_sd_status cb_get_sd_status)
{
	hDB = (DBCONTENT*)OAL_malloc(sizeof(DBCONTENT));
	if(hDB == 0)
	{
		return -1;
	}

	memset(hDB, 0, sizeof(DBCONTENT));

	hDB->cb = cb;
	hDB->cb_get_sd_status = cb_get_sd_status;

	hDB->mutex = OAL_mutex_create();
	if(hDB->mutex == 0)
	{
		return -1;
	}

	return init_check();
}

void _db_free()
{
	if(hDB)
	{
		save_content();
		if(hDB->mutex)
		{
			OAL_mutex_destroy(&hDB->mutex);
			hDB->mutex = 0;
		}
		f_close(&hDB->fdb);
		OAL_free(hDB);
		hDB = 0;
	}
}

int _db_mount(void)
{
	return init_check();
}

int _db_unmount(void)
{
	f_close(&hDB->fdb);
	hDB->mount = 0;
	return 0;
}

int save_content()
{
	int res = 0;
	unsigned int br;
	FIL f;

	res += f_open(&f, (const char*)F_DBCONTENT, (unsigned char)(FA_WRITE));
	if (res != FR_OK)return res;
	hDB->sd_free_clst = get_free_clst();
	res += f_write(&f, hDB, sizeof(DBCONTENT), &br);
	res += f_close(&f);
	return res;
}

int load_content()
{
	int res = 0;
	unsigned int br;
	FIL f;

	res += f_open(&f, (const char*)F_DBCONTENT, (unsigned char)(FA_READ));
	if (res != FR_OK)return res;
	res += f_read(&f, hDB, CONTENTSIZE, &br);
	res += f_close(&f);
	return res;
}

int init_check(void)
{
	int i;
	int res = 0;
	int exist[12];
	int integrity = 0;

	// 1、is mount?

	if (!is_mounted())
	{
		hDB->mount = 0;
		return 0;
	}

	hDB->mount = 1;

	// 2、完整性检查，3个目录，9个文件，并且检查剩余空间是否足够创建这些文件

	exist[0]  = db_is_file_exist(DBROOT			);
	exist[1]  = db_is_file_exist(WAVEROOT		);
	exist[2]  = db_is_file_exist(EBROOT			);
	exist[3]  = db_is_file_exist(F_DBCONTENT	);
	exist[4]  = db_is_file_exist(F_DBAUDIO		);
	exist[5]  = db_is_file_exist(F_DBVIDEO		);
	exist[6]  = db_is_file_exist(F_DBIMAGE		);
	exist[7]  = db_is_file_exist(F_DBEBOOK		);
	exist[8]  = db_is_file_exist(F_DBWAVE		);
	exist[9] = db_is_file_exist(F_DBLIKE		);
	exist[10] = db_is_file_exist(F_DBTAG		);

	for(i=0; i<11; i++)
	{
		if(exist[i])
		{
			integrity = 1;
			break;
		}
	}

	if(integrity)
	{
		//如果db不完整，需要重新构建db，并且首先检查剩余空间是否足够创建这些文件
		res += _db_reset();
	}
	else
	{
		res += load_content();
		if (FR_OK == res)
		{
			//3、如果db完整，要进一步做版本检查
			// if (hDB->version == 0)
   			// {
    		// 	res += -777;
   			// }
   			if (hDB->version != DB_VERSION)
			{
				//如果版本有更新，则重新构建db
				res += _db_reset();
			}
			else
			{
				// 4、诊断离线修改
				if (hDB->sd_free_clst != get_free_clst())
				{
					hDB->dirty = MODULE_ALL;
					hDB->ebookSN = 0;
					hDB->audio_count = 0;
					hDB->album_count = 0;
					hDB->artist_count = 0;
					hDB->video_count = 0;
					hDB->image_count = 0;
					hDB->ebook_count = 0;
					hDB->wave_count = 0;
					hDB->tag_count = 0;
					memset(hDB->like_count, 0, sizeof(hDB->like_count));

					f_unlink(F_DBFOLDER0);
					f_unlink(F_DBFOLDER1);
					f_unlink(F_DBFOLDER2);
					f_unlink(F_DBFOLDER3);
					f_unlink(F_DBFOLDER4);
					f_unlink(F_DBFOLDER5);
					f_unlink(F_DBFOLDER6);
					f_unlink(F_DBFOLDER7);
					f_unlink(F_FPL);
				}
			}
		}
	}

	return res;
}

int _db_reset(void)
{	DWORD nclst;
	DWORD clust_size;
	int res = 0;
	res += ext_get_free_(&nclst,&clust_size);
	if((nclst * clust_size/2)< 32*1024)	return -100; // less than 32MB bytes
	unsigned br;
	FIL f;

	memset(hDB, 0, CONTENTSIZE);

	clear_dir((const char*)EBROOT);
	clear_dir((const char*)DBROOT);

	if (res)	return -101;
	hDB->sector_size = clust_size * 512;

	if (db_is_file_exist(DBROOT))
	{
		res += f_mkdir(DBROOT);
		if (res)	return -99;
	}

	if (db_is_file_exist(WAVEROOT))
	{
		res += f_mkdir(WAVEROOT);
		if (res)	return -98;
	}
	if (db_is_file_exist(EBROOT))
	{
		res += f_mkdir(EBROOT);
		if (res) return -97;
	}

	if (db_is_file_exist(F_DBCONTENT))
	{
		hDB->version = DB_VERSION;
		hDB->dirty = MODULE_ALL;
		hDB->sd_free_clst = get_free_clst();
		res += f_open(&f, (const char*)(F_DBCONTENT), (unsigned char)(FA_READ | FA_WRITE | FA_CREATE_ALWAYS));
		res += f_write(&f, hDB, sizeof(DBCONTENT), &br);
		res += f_close(&f);
		if (res) return -96;
	}
	
	if (db_is_file_exist(F_DBAUDIO))
	{
		long long len = sizeof(AUDIORECORD) * MAXRECORD;

		res += f_open(&f, (const char*)(F_DBAUDIO), (unsigned char)(FA_READ | FA_WRITE | FA_CREATE_ALWAYS));
		res += f_lseek(&f, len - sizeof(long long));
		res += f_write(&f, &len, sizeof(long long), &br);
		res += f_close(&f);
		if (res) return -95;
	}
	
	if (db_is_file_exist(F_ALBUM))
	{
		long long len = sizeof(ALBUMINDEX) * MAXRECORD;
		len += sizeof(int) * MAXRECORD;

		res += f_open(&f, (const char*)(F_ALBUM), (unsigned char)(FA_READ | FA_WRITE | FA_CREATE_ALWAYS));
		res += f_lseek(&f, len - sizeof(long long));
		res += f_write(&f, &len, sizeof(long long), &br);
		res += f_close(&f);
		if (res) return -95;
	}
	
	if (db_is_file_exist(F_ARTIST))
	{
		long long len = sizeof(ARTISTINDEX) * MAXRECORD;
		len += sizeof(int) * MAXRECORD;

		res += f_open(&f, (const char*)(F_ARTIST), (unsigned char)(FA_READ | FA_WRITE | FA_CREATE_ALWAYS));
		res += f_lseek(&f, len - sizeof(long long));
		res += f_write(&f, &len, sizeof(long long), &br);
		res += f_close(&f);
		if (res) return -95;
	}
	
	if (db_is_file_exist(F_DBVIDEO))
	{
		long long len = sizeof(VIDEORECORD) * MAXRECORD;

		res += f_open(&f, (const char*)(F_DBVIDEO), (unsigned char)(FA_READ | FA_WRITE | FA_CREATE_ALWAYS));
		res += f_lseek(&f, len - sizeof(long long));
		res += f_write(&f, &len, sizeof(long long), &br);
		res += f_close(&f);
		if (res) return -94;
	}
	
	if (db_is_file_exist(F_DBIMAGE))
	{
		long long len = sizeof(IMAGERECORD) * MAXRECORD;

		res += f_open(&f, (const char*)(F_DBIMAGE), (unsigned char)(FA_READ | FA_WRITE | FA_CREATE_ALWAYS));
		res += f_lseek(&f, len - sizeof(long long));
		res += f_write(&f, &len, sizeof(long long), &br);
		res += f_close(&f);
		if (res) return -93;
	}
	
	if (db_is_file_exist(F_DBEBOOK))
	{
		long long len = sizeof(EBOOKRECORD) * MAXRECORD;

		res += f_open(&f, (const char*)(F_DBEBOOK), (unsigned char)(FA_READ | FA_WRITE | FA_CREATE_ALWAYS));
		res += f_lseek(&f, len - sizeof(long long));
		res += f_write(&f, &len, sizeof(long long), &br);
		res += f_close(&f);
		if (res) return -92;
	}

	if (db_is_file_exist(F_DBWAVE))
	{
		long long len = sizeof(WAVERECORD) * MAXRECORD;

		res += f_open(&f, (const char*)(F_DBWAVE), (unsigned char)(FA_READ | FA_WRITE | FA_CREATE_ALWAYS));
		res += f_lseek(&f, len - sizeof(long long));
		res += f_write(&f, &len, sizeof(long long), &br);
		res += f_close(&f);
		if (res) return -91;
	}

	if (db_is_file_exist(F_DBLIKE))
	{
		long long len = sizeof(LIKERECORD) * MAXLIKERECORD * MAXLIKETYPE;

		res += f_open(&f, (const char*)(F_DBLIKE), (unsigned char)(FA_READ | FA_WRITE | FA_CREATE_ALWAYS));
		res += f_lseek(&f, len - sizeof(long long));
		res += f_write(&f, &len, sizeof(long long), &br);
		res += f_close(&f);
		if (res) return -89;
	}

	if (db_is_file_exist(F_DBTAG))
	{
		long long len = sizeof(TAGRECORD) * MAXRECORD;

		res += f_open(&f, (const char*)(F_DBTAG), (unsigned char)(FA_READ | FA_WRITE | FA_CREATE_ALWAYS));
		res += f_lseek(&f, len - sizeof(long long));
		res += f_write(&f, &len, sizeof(long long), &br);
		res += f_close(&f);
		if (res) return -88;
	}

	return res;
}

#if SORT == 1
void _db_sort(SORTNODE * tmp, int rec_cnt)
{
	SORTNODE swap;
	int i,j;
	for(i=0; i<rec_cnt-1; i++)
	{
		for(j=i+1; j<rec_cnt; j++)
		{
			if( (tmp[j].id[0] < tmp[i].id[0]) ||
				(tmp[j].id[0] == tmp[i].id[0] && tmp[j].id[1] < tmp[i].id[1]))
			{
				swap.id[0] = tmp[i].id[0];
				swap.id[1] = tmp[i].id[1];
				swap.offset= tmp[i].offset;
				tmp[i].id[0]  = tmp[j].id[0] ;
				tmp[i].id[1]  = tmp[j].id[1] ;
				tmp[i].offset = tmp[j].offset;
				tmp[j].id[0]  = swap.id[0] ;
				tmp[j].id[1]  = swap.id[1] ;
				tmp[j].offset = swap.offset;
			}
		}
	}
}
#endif
